#include "lua_app.h"
#include "global_config.h"
#include <LuaWrapper.h>
#include <LittleFS.h>
#include <string.h> // strrchr()函数
#include <ntp_time.h>
#define FORMAT_SPIFFS_IF_FAILED true
LuaWrapper lua;
LuaApp luaApp; 

// static int myFunction(lua_State *lua_state) {
//     Serial.println("Hi from my C function");
//     return 0;
// }

// void blink() {
//     digitalWrite(LED_BUILTIN_PIN, HIGH);
//     delay(1500);
//     digitalWrite(LED_BUILTIN_PIN, LOW);
// }

static int lua_wrapper_pinMode(lua_State *lua_state) {
  int a = luaL_checkinteger(lua_state, 1);
  int b = luaL_checkinteger(lua_state, 2);
  pinMode(a, b);
  return 0;
}

static int lua_wrapper_digitalWrite(lua_State *lua_state) {
  int a = luaL_checkinteger(lua_state, 1);
  int b = luaL_checkinteger(lua_state, 2);
  digitalWrite(a, b);
  return 0;
}
  
static int lua_wrapper_delay(lua_State *lua_state) {
  int a = luaL_checkinteger(lua_state, 1);
  delay(a);
  return 0;
}

static int lua_wrapper_millis(lua_State *lua_state) {
  lua_pushnumber(lua_state, (lua_Number) millis());
  return 1;
}

static int lua_wrapper_getTime(lua_State *lua_state) {
  lua_pushstring(lua_state, ntpTime.getTime().c_str());
  return 1;
}

void LuaApp::register_funcs() {
    Serial.println("注册本地函数..");
      // pinMode(BTN_BOOT_PIN, INPUT);
    // pinMode(LED_BUILTIN_PIN, OUTPUT);
    // lua.Lua_register("myFunction", (const lua_CFunction) &myFunction);
    // lua.Lua_register("blink", (const lua_CFunction) &blink);
    lua.Lua_register("get_time", (const lua_CFunction) &lua_wrapper_getTime);

    lua.Lua_register("pinMode", (const lua_CFunction) &lua_wrapper_pinMode);
    lua.Lua_register("digitalWrite", (const lua_CFunction) &lua_wrapper_digitalWrite);
    lua.Lua_register("delay", (const lua_CFunction) &lua_wrapper_delay);
    lua.Lua_register("millis", (const lua_CFunction) &lua_wrapper_millis);
}


/**
 * 获取文件扩展名
 */
const char *get_file_extension(const char *filename) {
    const char *dot = strrchr(filename, '.');
    if (!dot || dot == filename) return "";
    return dot + 1;
}

/**
 * 加载lua脚本
 */
void show_lua_app_status(const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\r\n", dirname);
    if(!LittleFS.begin()){
    Serial.println("An Error has occurred while mounting LittleFS");
    return;
  }
    File root = LittleFS.open(dirname);
    if(!root){
        Serial.println("- failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println(" - not a directory");
        return;
    }

    File file = root.openNextFile();
    Serial.println("=========================APP FILE List===================================");
    while(file){
        if(file.isDirectory()){
            Serial.print("DIR : ");
            Serial.println(file.name()); 
            if(levels){
                show_lua_app_status(file.path(), levels -1);
            }
        } else {
            Serial.print("APP NAME: ");
            Serial.print(file.name());
            Serial.print("\tSIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
    Serial.println("=========================END APP FILE List===================================");
}

/**
 * 加载lua脚本
 */
void load_lua_script(const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\r\n", dirname);
    if(!LittleFS.begin()){
    Serial.println("An Error has occurred while mounting LittleFS");
    return;
  }
    File root = LittleFS.open(dirname);
    if(!root){
        Serial.println("- failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println(" - not a directory");
        return;
    }

    Serial.println("Start load lua script");
    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("DIR : ");
            Serial.println(file.name()); 
            if(levels){
                load_lua_script(file.path(), levels -1);
            }
        } else {
            Serial.print("\n\nload app: ");
            Serial.print(file.name());
            Serial.println("\n=========================SOURCE CODE===================================");
            if( strcmp(get_file_extension(file.name()), "lua") == 0 ) {
              //加载lua脚本
              String script = "";
              while(file.available()) {
                  char c = file.read();
                  script += c;
              }
              Serial.print("  Lua script:");
              Serial.println(script);
              Serial.println("==========================END SOURCE CODE==================================");
              Serial.println("==========================APP LOG==========================================");
              Serial.println(lua.Lua_dostring(&script));
              Serial.println("==========================END LOG====================================");
            } else
            {
              Serial.println("  Not a lua file");
            }
        }
        file = root.openNextFile();
    }
}

void LuaApp::load_apps() {
    //load lua script
  
}
void LuaApp::init() {
    //初始化lua环境
    register_funcs();
    //加载APP lua脚本
    show_lua_app_status(LUA_APP_PATH, 4);
    load_lua_script(LUA_APP_PATH, 4);
}

void LuaApp::update() {
    // String script = String("print('Hello world!')");
    // Serial.println(lua.Lua_dostring(&script));

    // script = String("print('Lua invoke blink()') blink()");
    // Serial.println(lua.Lua_dostring(&script));

    // lua.Lua_dostring(&script);

    String script = "";
    char c = 0;
    Serial.println();
    Serial.println("# Enter the lua script and press Control-D when finished:");
    while(1) {
        if(Serial.available() > 0) {
            c = Serial.read();
            if(c == 4) {
                break;
            }
            Serial.write(c);
            script += c;
            if(c == '\r') {
                Serial.write('\n');
                script += '\n';
            }
        }
    }
    if(script.length() > 0) {
      Serial.println();
      Serial.println("# Executing script:");
      Serial.println(lua.Lua_dostring(&script));
    }
}